%{
#include <stdio.h> /* For printf, etc. */
#include <math.h> /* For pow, used in the grammar. */
#include <malloc.h>
#include "calc.h" /* Contains definition of ’symrec’. */
int yylex (void);
fnctres res;
%}
%defines
%define parse.trace
%union{
double numt;
symrec *symt;
double expt;
arglst_t *arglstt;
}
%token <numt> NUM /* Simple double precision number. */
%token <symt> VAR FNCT /* Symbol table pointer: variable and function.*/
%type <expt> exp
%type <arglstt> arglst
%precedence '='
%left '-' '+'
%left '*' '/'
%precedence NEG /* negation--unary minus */
%right '^' /* exponentiation */

%destructor {discard_arglst($$);} arglst   // Notice that if "exp" is erroneous inside the rule "arglst: arglst ',' exp", right-hand-side "arglst" will be grabbed by this destructor.

%% /* The grammar follows. */
input:
%empty
| input line
;
line:
'\n'
| exp '\n' { printf ("%.10g\n", $1); }
| error '\n' { yyerrok; }   // TODO semantic value of symbols with symrec * type popped during error recovery should be freed. More important so of the terminals discarded thru the end of the recovery, for the lexer'll allocate space for them unnecessary.
;
exp:
NUM { $$ = $1; }
| VAR { $$ = $1->value.var; }
| VAR '=' exp { $$ = $3; $1->value.var = $3; }
| FNCT '(' arglst ')' { res = fnctcall($1, $3); if(res.stat==-1)YYERROR; discard_arglst($3);$$=res.val;/*executed only if YYERROR didn't.*/ }   // errors from fnctcall() handled by up-sitting rule.
| exp '+' exp { $$ = $1 + $3; }
| exp '-' exp { $$ = $1 - $3; }
| exp '*' exp { $$ = $1 * $3; }
| exp '/' exp { $$ = $1 / $3; }
| '-' exp %prec NEG { $$ = -$2; }
| exp '^' exp { $$ = pow ($1, $3); }
| '(' exp ')' { $$ = $2; }
;
arglst:
exp {$$ = create_arglst($1);}
| arglst ',' exp {$$ = append_arg($1, $3);}
;
/* End of grammar. */
%%
#include <ctype.h>
int
yylex (void)
{
int c;
/* Ignore white space, get first nonwhite character. */
while ((c = getchar ()) == ' ' || c == '\t')
continue;
if (c == EOF)
return 0;
/* Char starts a number => parse the number. */
if (c == '.' || isdigit (c))
{
ungetc (c, stdin);
scanf ("%lf", &yylval.numt);
return NUM;
}

/* Char starts an identifier => read the name. */
if (isalpha (c))
{
/* Initially make the buffer long enough
for a 40-character symbol name. */
static size_t length = 40;
static char *symbuf = 0;
symrec *s;
int i;
if (!symbuf)
symbuf = (char *) malloc (length + 1);
i = 0;

do
{
/* If buffer is full, make it bigger. */
if (i == length)
{
length *= 2;
symbuf = (char *) realloc (symbuf, length + 1);
}
/* Add this character to the buffer. */
symbuf[i++] = c;
/* Get another character. */
c = getchar ();
}
while (isalnum (c));
ungetc (c, stdin);
symbuf[i] = '\0';
s = getsym (symbuf);
if (s == 0)
s = putsym (symbuf, VAR);
yylval.symt = s;
return s->type;
}
/* Any other character is a token by itself. */
return c;
}
